// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_error.h"
#include "mk_scene_node.h"
#include "mk_entity.h"

namespace MK3DE
{
	CSceneNode::CSceneNode(CSceneNode* parent)
	{
		_parent = parent;
	}

	CSceneNode::~CSceneNode()
	{
		RemoveAllChild();

		std::vector<CEntity*>::iterator i = _vecEntity.begin(); 
		while (i != _vecEntity.end())
		{
			CEntity* entity = *i;
			entity->_AttachSceneNode(NULL);
			SAFE_DELETE(entity);

			++i;
		}

		_vecEntity.clear();
	}

	void CSceneNode::Update(DWORD dt, BOOL bChanged)
	{
		D3DXMATRIX* pParentTransform = NULL;
		if (_parent)
			pParentTransform = &_parent->GetAbsoluteTransformation();

		BOOL changed = UpdateAbsoluteTransformation(pParentTransform);
		if (bChanged)
			changed = TRUE;

		// update all entities.
		_UpdateAllEntities(dt, changed);

		// update all children.
		_UpdateAllChildren(dt, changed);
	}

	void CSceneNode::_UpdateAllEntities(DWORD dt, BOOL bChanged)
	{
		std::vector<CEntity*>::iterator itEntity = _vecEntity.begin();
		while (itEntity != _vecEntity.end())
		{
			CEntity* pEntity = *itEntity;
			pEntity->Update(dt, bChanged);
			++itEntity;
		}
	}

	void CSceneNode::_UpdateAllChildren(DWORD dt, BOOL bChanged)
	{
		std::vector<CSceneNode*>::iterator itSceneNode = _vecChild.begin();
		while (itSceneNode != _vecChild.end())
		{
			CSceneNode* pSceneNode = *itSceneNode;
			pSceneNode->Update(dt, bChanged);
			++itSceneNode;
		}
	}

	CSceneNode* CSceneNode::GetChild(DWORD idx)
	{
		if (idx < (DWORD)_vecChild.size())
			return _vecChild[idx];
		return NULL;
	}

	void CSceneNode::AddChild(CSceneNode* child)
	{
		CSceneNode* parent = child->GetParent();
		ASSERT(parent);
		parent->RemoveChild(child);
		_vecChild.push_back(child);
		child->AddRef();
	}

	BOOL CSceneNode::RemoveChild(CSceneNode* child)
	{
		std::vector<CSceneNode*>::iterator i = _vecChild.begin();
		while (i != _vecChild.end())
		{
			CSceneNode* sceneNode = *i;
			if (sceneNode == child)
			{
				_vecChild.erase(i);
				SAFE_RELEASE(sceneNode);
				return TRUE;
			}

			++i;
		}

		return FALSE;
	}

	void CSceneNode::RemoveAllChild()
	{
		std::vector<CSceneNode*>::iterator itSceneNode = _vecChild.begin();
		while (itSceneNode != _vecChild.end())
		{
			CSceneNode* pSceneNode = *itSceneNode;
			SAFE_RELEASE(pSceneNode);
			++itSceneNode;
		}

		_vecChild.clear();
	}

	void CSceneNode::AttachEntity(CEntity* entity)
	{
		CSceneNode* parent = entity->GetAttachedSceneNode();
		if (parent)
			parent->DeatachEntity(entity);

		entity->_AttachSceneNode(this);
		_vecEntity.push_back(entity);
	}

	BOOL CSceneNode::DeatachEntity(CEntity* entity)
	{
		CSceneNode* parent = entity->GetAttachedSceneNode();
		if (!parent)
			return FALSE;

		entity->_AttachSceneNode(NULL);
		std::vector<CEntity*>::iterator i = _vecEntity.begin(); 
		while (i != _vecEntity.end())
		{
			if ((*i) == entity)
			{
				_vecEntity.erase(i);
				return TRUE;
			}

			++i;
		}

		return FALSE;
	}

	void CSceneNode::DeatachAllEntity()
	{
		std::vector<CEntity*>::iterator i = _vecEntity.begin(); 
		while (i != _vecEntity.end())
		{
			CEntity* entity = *i;
			entity->_AttachSceneNode(NULL);

			++i;
		}

		_vecEntity.clear();
	}

	CEntity* CSceneNode::GetEntity(DWORD idx)
	{
		if (idx < (DWORD)_vecEntity.size())
			return _vecEntity[idx];
		return NULL;
	}


	//--------------------------------------------
	//DWORD CSceneNode::_sId = 0;

	//CSceneNode::CSceneNode(CSceneNode* parent)
	//{
	//       _parent = parent;
	//       _bShadowCast = FALSE;
	//       _bShadowReceive = FALSE;
	//       _bReflection = TRUE;
	//       _bRefraction = TRUE;
	//       _bVisible = TRUE;
	//       _renderQueueType = RQT_SOLID;

	//	_id = __AllocId();
	//}

	//CSceneNode::~CSceneNode()
	//{
	//	DeleteAllChild();
	//}

	//BOOL CSceneNode::PreRender()
	//{
	//       if (!_bVisible)
	//           return TRUE;

	//       CEngine* engine = GetEngine();
	//       CSceneManager* sceneManager = engine->GetSceneManager();
	//       RENDER_STAGE renderStage = sceneManager->GetRenderStage();

	//       if (renderStage == RS_REFLECTION && !_bReflection)
	//           return TRUE;

	//       if (renderStage == RS_REFRACTION && !_bRefraction)
	//           return TRUE;

	//       if (engine->GetCamera()->TestFrustumAABB(_aabb))
	//           engine->GetSceneManager()->_AddToRenderQueue(this);

	//       std::vector<CSceneNode*>::iterator i = _vecChild.begin();
	//	while (i != _vecChild.end())
	//	{
	//		CSceneNode* node = *i;
	//		if (!node->PreRender())
	//			GetEngine()->GetLog()->Write(MKLT_INFO, "Pre render scene node[type: %d, id: %d] failed.", node->GetType(), node->GetId());
	//		++i;
	//	}

	//	return TRUE;
	//}

	//BOOL CSceneNode::Render()
	//{
	//       if (!_bVisible)
	//           return TRUE;

	//	return TRUE;
	//}

	//BOOL CSceneNode::PostRender()
	//{
	//       if (!_bVisible)
	//           return TRUE;

	//	std::vector<CSceneNode*>::iterator i = _vecChild.begin();
	//	while (i != _vecChild.end())
	//	{
	//		CSceneNode* node = *i;
	//		if (!node->PostRender())
	//			GetEngine()->GetLog()->Write(MKLT_INFO, "Post render scene node[type: %d, id: %d] failed.", node->GetType(), node->GetId());
	//		++i;
	//	}

	//	return TRUE;
	//}

	//BOOL CSceneNode::RenderShadow(D3DXMATRIX& matView, D3DXMATRIX& matProj)
	//{
	//       if (!_bVisible)
	//           return TRUE;

	//	std::vector<CSceneNode*>::iterator i = _vecChild.begin();
	//	while (i != _vecChild.end())
	//	{
	//		CSceneNode* node = *i;
	//		if (!node->RenderShadow(matView, matProj))
	//			GetEngine()->GetLog()->Write(MKLT_INFO, "Render scene node[type: %d, id: %d] shadow failed.", node->GetType(), node->GetId());
	//		++i;
	//	}

	//	return TRUE;
	//}

	//void CSceneNode::Update(DWORD dt)
	//{
	//	std::vector<CSceneNode*>::iterator i = _vecChild.begin();
	//	while (i != _vecChild.end())
	//	{
	//		(*i)->Update(dt);
	//		++i;
	//	}
	//}

	//CSceneNode* CSceneNode::GetChildByIndex(DWORD idx)
	//{
	//	if (idx < _vecChild.size())
	//		return _vecChild[idx];
	//	return NULL;
	//}

	//CSceneNode* CSceneNode::GetChildById(DWORD id)
	//{
	//	std::vector<CSceneNode*>::iterator i = _vecChild.begin();
	//	while (i != _vecChild.end())
	//	{
	//		if ((*i)->GetId() == id)
	//			return *i;
	//		++i;
	//	}
	//	return NULL;
	//}

	//   CSceneNode* CSceneNode::GetChildByType(SCENE_NODE_TYPE type)
	//   {
	//       std::vector<CSceneNode*>::iterator i = _vecChild.begin();
	//       while (i != _vecChild.end())
	//       {
	//           if ((*i)->GetType() == type)
	//               return *i;
	//           ++i;
	//       }
	//       return NULL;
	//   }

	//void CSceneNode::AddChild(CSceneNode* node)
	//{
	//	CSceneNode* parent = node->GetParent();
	//	ASSERT(parent);
	//	parent->RemoveChild(node);
	//	_vecChild.push_back(node);
	//}

	//BOOL CSceneNode::RemoveChild(CSceneNode* node)
	//{
	//	std::vector<CSceneNode*>::iterator i = _vecChild.begin();
	//	while (i != _vecChild.end())
	//	{
	//		if ((*i) == node)
	//		{
	//			_vecChild.erase(i);
	//			return TRUE;
	//		}

	//		++i;
	//	}

	//	return FALSE;
	//}

	//void CSceneNode::DeleteAllChild()
	//{
	//	std::vector<CSceneNode*>::iterator i = _vecChild.begin();
	//	while (i != _vecChild.end())
	//	{
	//		CSceneNode* node = *i;
	//		SAFE_DELETE(node);
	//		++i;
	//	}
	//	_vecChild.clear();
	//}
}